#include "stdafx.h"
#include "schnorr_prover.h"
#include "schnorr_system.h"

schnorr_prover::schnorr_prover(const schnorr_system* const s)
	:parent_system(s)
{
	if(parent_system == NULL) throw "Not allowed create a prover before create a system";
	srand(unsigned(time(NULL)));
	generate_parameters();
}

schnorr_prover::schnorr_prover(const large_uint& private_key, const schnorr_system* const s)
	:parent_system(s)
{
	if(parent_system == NULL) throw "Not allowed create a prover before create a system";
	generate_parameters(private_key);
}

#define PUBLIC_P parent_system->get_p()
#define PUBLIC_Q parent_system->get_q()
#define PUBLIC_ALPHA parent_system->get_alpha()

void schnorr_prover::generate_parameters(const large_uint& private_key)
{
	if(private_key == 0)
		s = large_uint::random() % (PUBLIC_Q - 1) + 1;
	else
		s = private_key;

	v = large_uint::pow_m(PUBLIC_ALPHA.inv(PUBLIC_P), s, PUBLIC_P);
	
	printf("s = (%I64u; %I64u)\n", s._h, s._l);
	printf("v = alpha^-s %% p = (%I64u; %I64u)\n", v._h, v._l);
}

large_uint schnorr_prover::get_witness(const large_uint& random)
{
	if(random == 0)
		r = large_uint::random() % (PUBLIC_Q - 1) + 1;
	else
		r = random;

	large_uint x = large_uint::pow_m(PUBLIC_ALPHA, r, PUBLIC_P);

	printf("r = (%I64u; %I64u)\n", r._h, r._l);
	printf("x = (%I64u; %I64u)\n", x._h, x._l);

	return x;
}

large_uint schnorr_prover::get_response(const large_uint& e) const
{
	if(r==0) throw "Can't send a response before send the witness";
	return large_uint::add_m(r, large_uint::mult_m(s, e, PUBLIC_Q), PUBLIC_Q);
}

